package git.soulbgm.config;

import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.List;
import java.util.Properties;
import java.util.concurrent.CopyOnWriteArrayList;

import git.soulbgm.pojo.Backend;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * 代理服务器配置类
 *
 * <p>负责加载和管理代理服务器的配置信息，包括服务器端口、后端服务器列表、
 * 超时设置等配置参数。配置信息从配置文件（proxy.properties）中读取。</p>
 *
 * <p>配置项包括：</p>
 * <ul>
 *   <li>监听端口</li>
 *   <li>后端服务器列表</li>
 *   <li>连接超时时间</li>
 *   <li>健康检查间隔</li>
 *   <li>线程池参数</li>
 * </ul>
 *
 * @author soulbgm
 * @version 1.0
 * @since 1.0
 */
public class ProxyConfig {
    private static final Logger logger = LoggerFactory.getLogger(ProxyConfig.class);

    /**
     * 组播地址
     */
    private final String multicastAddress;
    /**
     * 组播端口
     */
    private final int multicastPort;
    /**
     * 后端服务器列表
     */
    private final List<Backend> backends;
    /**
     * UDP数据包缓冲区大小
     */
    private final int bufferSize;
    /**
     * 配置实例（单例模式）
     */
    private static volatile ProxyConfig instance;
    /**
     * 配置文件路径
     */
    private static final String CONFIG_FILE = "config/proxy.properties";

    /**
     * 获取组播地址
     *
     * @return 组播地址
     */
    public String getMulticastAddress() {
        return multicastAddress;
    }

    /**
     * 获取组播端口
     *
     * @return 组播端口
     */
    public int getMulticastPort() {
        return multicastPort;
    }

    /**
     * 获取后端服务器列表
     *
     * @return 后端服务器列表的只读视图
     */
    public List<Backend> getBackends() {
        return backends;
    }

    /**
     * 获取UDP数据包缓冲区大小
     *
     * @return 缓冲区大小（字节）
     */
    public int getBufferSize() {
        return bufferSize;
    }

    /**
     * 从Properties对象创建配置实例
     * <p>
     * 该构造方法负责解析配置文件中的各项参数，包括：
     * <ul>
     *     <li>multicast.address - 组播地址，默认值：239.255.255.250</li>
     *     <li>multicast.port - 组播端口，默认值：1900</li>
     *     <li>buffer.size - UDP缓冲区大小，默认值：65507</li>
     *     <li>backend.N.host - 第N个后端服务器的主机地址</li>
     *     <li>backend.N.port - 第N个后端服务器的端口号</li>
     * </ul>
     * </p>
     *
     * @param props 包含配置信息的Properties对象
     */
    private ProxyConfig(Properties props) {
        this.multicastAddress = props.getProperty("multicast.address", "239.255.255.250");
        this.multicastPort = Integer.parseInt(props.getProperty("multicast.port", "1900"));
        this.bufferSize = Integer.parseInt(props.getProperty("buffer.size", "65507"));

        this.backends = new CopyOnWriteArrayList<>();
        int backendIndex = 1;
        while (true) {
            String hostKey = "backend." + backendIndex + ".host";
            String portKey = "backend." + backendIndex + ".port";
            String host = props.getProperty(hostKey);
            String port = props.getProperty(portKey);

            if (host == null || port == null) {
                break;
            }

            backends.add(new Backend(host, Integer.parseInt(port)));
            backendIndex++;
        }
    }

    /**
     * 获取配置实例（单例模式）
     * <p>
     * 如果实例不存在，则创建新实例。使用双重检查锁定确保线程安全。
     * </p>
     *
     * @return 配置实例
     * @throws RuntimeException 如果配置文件加载失败
     */
    public static ProxyConfig getInstance() {
        if (instance == null) {
            synchronized (ProxyConfig.class) {
                if (instance == null) {
                    instance = loadConfig();
                }
            }
        }
        return instance;
    }

    /**
     * 加载配置文件
     * <p>
     * 首先尝试从classpath加载配置文件，如果失败则尝试从文件系统加载。
     * 配置文件使用properties格式。
     * </p>
     *
     * @return 新的配置实例
     * @throws RuntimeException 如果配置文件不存在或格式错误
     */
    private static ProxyConfig loadConfig() {
        Properties props = new Properties();

        // 首先尝试从文件系统加载
        try (FileInputStream fis = new FileInputStream(CONFIG_FILE)) {
            props.load(fis);
            return new ProxyConfig(props);
        } catch (IOException e) {
            logger.debug("无法加载配置文件: " + CONFIG_FILE, e);
        }

        // 尝试从classpath加载
        try (InputStream is = ProxyConfig.class.getClassLoader().getResourceAsStream(CONFIG_FILE)) {
            if (is != null) {
                props.load(is);
                return new ProxyConfig(props);
            } else {
                throw new RuntimeException("无法从classpath加载配置文件");
            }
        } catch (IOException e) {
            throw new RuntimeException("无法从classpath加载配置文件", e);
        }
    }

    /**
     * 重新加载配置
     * <p>
     * 从配置文件重新加载所有配置信息。这个方法是线程安全的，
     * 使用synchronized确保在重载过程中的一致性。
     * </p>
     *
     * @throws RuntimeException 如果重新加载配置失败
     */
    public static void reload() {
        synchronized (ProxyConfig.class) {
            instance = loadConfig();
        }
    }
} 